package com.medusa.aps.business.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import com.medusa.aps.business.common.fastjson2.FastJson2;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;


/**
 * @author xianhui.yu
 **/
public interface DateTimeUtils {

    /**
     * 月份 日期 时间格式
     */
    String MONTH_DAY_PATTERN = "MM-dd";

    /**
     * 月份 日期 时间格式formatter
     */
    DateTimeFormatter MONTH_DAY_FORMATTER = DateTimeFormatter.ofPattern(MONTH_DAY_PATTERN);

    /**
     * 时 分 时间格式
     */
    String HOUR_MINUTE_PATTERN = "HH:mm";

    /**
     * 时 分 时间格式formatter
     */
    DateTimeFormatter HOUR_MINUTE_FORMATTER = DateTimeFormatter.ofPattern(HOUR_MINUTE_PATTERN);

    /**
     * 日期描述 转换成 -》 日期 (星期几)格式
     *
     * @param date 日期
     * @return 日期 (星期几)格式
     */
    static String dateDesc(LocalDate date) {
        return StrUtil.format("{} ({})", date.format(DatePattern.NORM_DATE_FORMATTER), LocalDateTimeUtil.dayOfWeek(date).toChinese());
    }

    /**
     * 日期描述 转换成 -》 "%d年第%d周%s-%s"
     *
     * @param date 日期
     * @return "%d年第%d周%s-%s"
     */

    static String calendarYearDateOfWeek(LocalDate date) {
        LocalDate monDay = date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate sunday = date.with(TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
        return StrUtil.format("{}年第{}周{}-{}",
                date.getYear(),
                String.format("%02d", date.get(WeekFields.of(Locale.getDefault()).weekOfYear())),
                monDay.format(DateTimeUtils.MONTH_DAY_FORMATTER),
                sunday.format(DateTimeUtils.MONTH_DAY_FORMATTER)
        );
    }


    /**
     * 根据给定的日期范围,生成升序的日期序列.如果时间范围为空,则默认生成这样的序列:[当前日期,...,当前日期+30];
     * 如果开始日期为空且结束日期非空,则生成这样的序列:[结束日期-30,...,结束日期];
     * 如果结束日期为空且开始日期非空,则生成这样的序列:[开始日期,...,开始日期+30]
     * @param start 开始日期
     * @param end 结束日期
     * @return 升序的日期序列
     */
    static SortedSet<LocalDate> generateDatesHeader(LocalDate start, LocalDate end) {
        SortedSet<LocalDate> datesHeader = new TreeSet<>();
        if (start == null && end == null) {
            start = LocalDate.now();
            end = start.plusDays(29);
        } else if (start != null && end == null) {
            end = start.plusDays(29);
        } else if (start == null) {
            start = end.minusDays(29);
        }
        start.datesUntil(end.plusDays(1)).forEach(date -> datesHeader.add(date));
        return datesHeader;
    }

    /**
     * 根据给定的日期范围,步进1天生成升序的日期序列.
     * @param start 开始日期,不能为空
     * @param end 结束日期,不能为空
     * @return 升序的日期序列
     */
    static SortedSet<LocalDate> generateDatesRange(LocalDate start, LocalDate end) {
        SortedSet<LocalDate> datesRange = new TreeSet<>();
        if (start == null || end == null) {
            return datesRange;
        }
        start.datesUntil(end.plusDays(1)).forEach(date -> datesRange.add(date));
        return datesRange;
    }

    /**
     * 时间段转Duration
     * @param specificTime 时间段,[2024-01-15 09:00~2024-01-15 12:00, 2024-01-15 13:00~2024-01-15 18:00]
     *
     * @return 有序的Map
     */
    static SortedMap<LocalDate, Duration> strToDurationMap(String specificTime) {
        if (specificTime == null || specificTime.length() <= 2) {
            return new TreeMap<>();
        }
        //去掉前后的[]
        String substring = specificTime.substring(1, specificTime.length() - 1);
        List<String> strList = StrUtil.split(substring, StrPool.COMMA);
        if (CollUtil.isEmpty(strList)) {
            return new TreeMap<>();
        }
        SortedMap<LocalDate, Duration> durationMap = new TreeMap<>();
        strList.forEach(str -> {
            String[] split = str.trim().split("~");
            LocalDateTime startTime = LocalDateTime.parse(split[0], FastJson2.NO_SECONDS_DATETIME_FORMATTER);
            LocalDateTime endTime = LocalDateTime.parse(split[1], FastJson2.NO_SECONDS_DATETIME_FORMATTER);
            durationMap.put(startTime.toLocalDate(),
                    durationMap.getOrDefault(startTime.toLocalDate(), Duration.ZERO).plus(Duration.between(startTime, endTime)));
        });
        return durationMap;
    }

}
